package com.tsystems.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tsystems.common.CommonKeys;
import com.tsystems.entities.Employee;
import com.tsystems.entities.Passenger;
import com.tsystems.entities.Station;
import com.tsystems.entities.Ticket;
import com.tsystems.entities.TimeTableElement;
import com.tsystems.entities.Train;
import com.tsystems.services.EmployeeServices;
import com.tsystems.services.PassengerServices;
import com.tsystems.services.StationServices;
import com.tsystems.services.TicketServices;
import com.tsystems.services.TimeTableElementServices;
import com.tsystems.services.TrainServices;

public class ConnectionHandler implements Runnable {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	EmployeeServices employeeServices = EmployeeServices.getInstance();
	PassengerServices passengerServices = PassengerServices.getInstance();
	StationServices stationServices = StationServices.getInstance();
	TicketServices ticketServices = TicketServices.getInstance();
	TimeTableElementServices timeTableElementServices = TimeTableElementServices
			.getInstance();
	TrainServices trainServices = TrainServices.getInstance();

	private Socket socket;
	private String login;

	private ObjectOutputStream os;
	private ObjectInputStream is;

	public ConnectionHandler(Socket socket) {
		this.socket = socket;
	}

	public void run() {
		try {
			os = new ObjectOutputStream(socket.getOutputStream());
			is = new ObjectInputStream(socket.getInputStream());

			while (true) {
				CommonKeys code = (CommonKeys) is.readObject();

				switch (code) {
				case LOGIN:
					login = login();
					break;
				case ADD_STATION:
					addStation();
					break;
				case REGISTER:
					register();
					break;
				case FIND_TRAIN:
					findTrain();
					break;
				case GET_TIMETABLE:
					getTimeTable();
					break;
				case VIEW_TICKETS:
					viewTickets();
					break;
				case BUY_TICKETS:
					buyTicket();
					break;
				case LOGIN_EMPL:
					login = loginEmployee();
					break;
				case REGISTER_EMPL:
					registerEmployee();
					break;
				case ADD_TRAIN:
					addTrain();
					break;
				case ADD_TTE:
					addTTE();
					break;
				case VIEW_TTE:
					viewTTE();
					break;
				case VIEW_ARRIVAL_TTE:
					getArrivalTimeTable();
					break;
				case VIEW_PASSANGERS_ON_TRAIN:
					viewPassengersOnTrain();
					break;
				case VIEW_TRAINS:
					viewTrains();
					break;
				case VIEW_STATIONS:
					viewStations();
					break;
				case VIEW_PASSENGERS_BASE:
					viewPassengersBase();
					break;
				case REMOVE_PASSENGER:
					removePassenger();
					break;
				case EDIT_PASSENGER:
					editPassenger();
					break;
				case ADD_PASSENGER:
					addPassenger();
					break;
				case CLOSE:
					return;

				default:
					logger.error("No such message code");
				}
			}
		} catch (ClassNotFoundException e) {
			logger.error("ClassNotFoundException", e);
		} catch (IOException e) {
			logger.error("IOException", e);
		} finally {
			try {
				if (os != null) {
					os.close();
				}

				if (is != null) {
					is.close();
				}

				if (socket != null) {
					socket.close();
				}
			} catch (IOException e) {
				logger.error("IOException", e);
			}

			logger.info("Server close client connection");
		}
	}

	public String login() throws IOException, ClassNotFoundException {
		logger.info("LOGIN");
		String login = (String) is.readObject();
		String password = (String) is.readObject();
		logger.info("login = {}; password = {}", login, password);

		String result = passengerServices.login(login, password);

		logger.info(result);

		os.writeObject(result);
		os.flush();
		return login;

	}

	public void register() throws IOException, ClassNotFoundException {
		logger.info("REGISTER");
		Passenger passenger = (Passenger) is.readObject();

		String result = passengerServices.register(passenger);


		logger.info(result);

		os.writeObject(result);
		os.flush();
	}

	public String loginEmployee() throws IOException, ClassNotFoundException {
		logger.info("LOGIN_EMPL");
		String login = (String) is.readObject();
		String password = (String) is.readObject();
		logger.info("login = {}; password = {}", login, password);

		String result = employeeServices.loginEmployee(login, password);

		logger.info(result);

		os.writeObject(result);
		os.flush();
		return login;

	}

	public void registerEmployee() throws IOException, ClassNotFoundException {
		logger.info("REGISTER_EMPL");
		Employee employee = (Employee) is.readObject();

		String result = employeeServices.registerEmployee(employee);
		logger.info(result);

		os.writeObject(result);

		os.flush();
	}

	public void addStation() throws IOException, ClassNotFoundException {
		logger.info("ADD_STATION");
		Station employee = (Station) is.readObject();

		String result = stationServices.addStation(employee);

		logger.info(result);

		os.writeObject(result);
		os.flush();
	}

	public void addTTE() throws IOException, ClassNotFoundException {
		logger.info("ADD_TTE");
		TimeTableElement timeTableElement = (TimeTableElement) is.readObject();

		String result = timeTableElementServices
				.addTimeTableElement(timeTableElement);

		logger.info(result);

		os.writeObject(result);
		os.flush();
	}

	public void addPassenger() throws IOException, ClassNotFoundException {

		logger.info("ADD_PASSENGER");
		Passenger passenger = (Passenger) is.readObject();

		String result = passengerServices.register(passenger);
		logger.info(result);

		os.writeObject(result);
		os.flush();

	}

	public void findTrain() throws ClassNotFoundException, IOException {

		logger.info("FIND_TRAIN");

		Station stationA = (Station) is.readObject();
		Station stationB = (Station) is.readObject();
		Date timeA = (Date) is.readObject();
		Date timeB = (Date) is.readObject();

		HashMap<Train, List<TimeTableElement>> result = timeTableElementServices
				.findTrain(stationA, stationB, timeA, timeB);

		if (!result.isEmpty()) {
			logger.info("train found");
		} else {
			logger.info("train not found");
		}

		os.writeObject(result);
		os.flush();

	}

	public void getTimeTable() throws IOException, ClassNotFoundException {

		logger.info("GET_TIMETABLE");

		Station station = (Station) is.readObject();

		List<TimeTableElement> result = timeTableElementServices
				.getTimeTable(station);

		os.writeObject(result);
		os.flush();

	}

	public void getArrivalTimeTable() throws IOException,
			ClassNotFoundException {

		logger.info("GET_ARRIVAL_TIMETABLE");

		Station station = (Station) is.readObject();

		List<TimeTableElement> result = timeTableElementServices
				.getTimeTable(station);

		os.writeObject(result);
		os.flush();

	}

	public void viewTickets() throws IOException {

		logger.info("VIEW_TICKETS");
		List<Ticket> result = ticketServices.viewTickets(login);

		os.writeObject(result);
		os.flush();

	}

	public void buyTicket() throws ClassNotFoundException, IOException {

		logger.info("BUY_TICKETS");

		Station fromStation = (Station) is.readObject();
		Station toStation = (Station) is.readObject();
		Date fromTime = (Date) is.readObject();
		Train train = (Train) is.readObject();
		Date arrivalTime = (Date) is.readObject();

		String result = ticketServices.buyTicket(fromStation, toStation,
				fromTime, train, arrivalTime, login);

		logger.info(result);
		
		os.writeObject(result);
		os.flush();

	}

	public void removePassenger() throws ClassNotFoundException, IOException {

		logger.info("REMOVE_PASSENGER");
		Passenger passenger = (Passenger) is.readObject();

		String result = passengerServices.removePassenger(passenger);

		logger.info(result);

		os.writeObject(result);
		os.flush();

	}

	public void editPassenger() throws ClassNotFoundException, IOException {

		logger.info("EDIT_PASSENGER");
		Passenger passenger = (Passenger) is.readObject();

		String result = passengerServices.editPassenger(passenger);

		logger.info(result);

		os.writeObject(result);
		os.flush();

	}

	public void viewPassengersBase() throws IOException {

		logger.info("VIEW_PASSENGERS_BASE");

		List<Passenger> result = passengerServices.viewPassengersBase();

		if (result.isEmpty()) {
			logger.info("passenger base empty");
		} else {
			logger.info("passenger base not empty");
		}
		os.writeObject(result);
		os.flush();

	}

	public void viewTrains() throws IOException {

		logger.info("VIEW_TRAINS");

		List<Train> result = trainServices.viewTrains();

		if (result.isEmpty()) {
			logger.info("trains base empty");
		} else {
			logger.info("trains base not empty");
		}

		os.writeObject(result);
		os.flush();

	}

	public void viewStations() throws IOException {

		logger.info("VIEW_STATIONS");

		List<Station> result = stationServices.viewStations();

		if (result.isEmpty()) {
			logger.info("stations base empty");
		} else {
			logger.info("stations base not empty");
		}

		os.writeObject(result);
		os.flush();

	}

	public void viewTTE() throws IOException {

		logger.info("VIEW_TTE");

		List<TimeTableElement> result = timeTableElementServices
				.viewTimeTableElementsBase();

		if (result.isEmpty()) {
			logger.info("tte base empty");
		} else {
			logger.info("tte base not empty");
		}

		os.writeObject(result);
		os.flush();

	}

	public void viewPassengersOnTrain() throws ClassNotFoundException,
			IOException {

		logger.info("VIEW_PASSANGERS_ON_TRAIN");

		TimeTableElement timeTableElement = (TimeTableElement) is.readObject();

		List<Passenger> result = passengerServices
				.viewPassengersOnTrain(timeTableElement);

		if (result.isEmpty()) {
			logger.info("no passangers on this train");
		} else {
			logger.info("passangers found");
		}

		os.writeObject(result);
		os.flush();

	}

	public void addTrain() throws ClassNotFoundException, IOException {

		logger.info("ADD_TRAIN");
		Train train = (Train) is.readObject();

		String result = trainServices.addTrain(train);

		logger.info(result);
		
		os.writeObject(result);
		os.flush();

	}

}
